/*
 * ProcesadordeTareas.cpp
 *
 *  Created on: 19/10/2012
 *      Author: emmanuel
 */

#include "ProcesadordeTareas.h"

ProcesadordeTareas::ProcesadordeTareas(string dir_raiz){

	this->logger = new Logger("log_procesador.txt");

	this->directorio_raiz = "";
	if (!dir_raiz.empty())
		this->directorio_raiz = dir_raiz + "/";


	this->path_diccionario =  this->directorio_raiz + PATH_DICC_INPUT;
	this->path_frases = this->directorio_raiz + PATH_FRASES_INPUT;
	this->path_stopwords = this->directorio_raiz + PATH_STOPWORDS_INPUT;
	this->path_arbol = "";
	this->path_hash = this->directorio_raiz + PATH_DOWLOAD;

	this->logger->log(DEBUG, "Procesador: " + this->path_diccionario);
	this->logger->log(DEBUG, "Procesador: " + this->path_frases);
	this->logger->log(DEBUG, "Procesador: " + this->path_stopwords);

	this->terminos_guardados = 0;

	this->arbol = NULL;
	this->hash = NULL;

	this->borrar_directorios();
	this->crear_directorios();

	this->crear_hash_frases();
	this->normalizar_diccionario();
	this->indexar_diccionario_aleatorio();
	this->ordenar_diccionario_aleatorio();

}

void ProcesadordeTareas::borrar_directorios(){
	Directorio::borrar_directorio(this->directorio_raiz + DIR_DICC);
	Directorio::borrar_directorio(this->directorio_raiz + DIR_HASH);
	Directorio::borrar_directorio(this->directorio_raiz + DIR_ARBOL);
}

void ProcesadordeTareas::crear_directorios(){
	Directorio::crear_carpeta("", this->directorio_raiz + DIR_DICC);
	Directorio::crear_carpeta("", this->directorio_raiz + DIR_HASH);
	Directorio::crear_carpeta("", this->directorio_raiz + DIR_ARBOL);
}

/* lee el archivo de frases crea el hash de las mismas por el identificador aleatorio */
void ProcesadordeTareas::crear_hash_frases(){
	this->hash = new Hash(this->directorio_raiz);

	FrasesFile * file = new FrasesFile(this->directorio_raiz + PATH_FRASES_INPUT);
	RecordFrase * record = NULL;
	int cantidad = 0;
	while(!file->is_EOF()){
		record = file->leer_registro();
		if(record->getTamanio() <= 256)
			this->hash->insertar_registro(*record);
		if(cantidad == 255)
			break;
		cantidad++;
	}

	this->crear_archivo_frases_long_fija();
}

void ProcesadordeTareas::crear_archivo_frases_long_fija(){

	int long_frase = 256;
	int long_mapa = 256;
	ArchivoBinario::crear("F.bin");
	ArchivoBinario archivo("F.bin", RW);


	MapaEspacioLibre mapa;
	char bufferMapa[long_mapa];
	for (int i = 0; i < long_mapa; i++)
		bufferMapa[0] = '0';
	archivo.write(bufferMapa,long_mapa);
	int id = 1;
	try{
	for (int i = 0; i < this->hash->get_cantidad_cubos(); i++){
		list<RecordFrase>::iterator itrecord;
		list<RecordFrase> frases = this->hash->get_frases_en_cubo(i);
		for(itrecord = frases.begin(); itrecord != frases.end(); ++itrecord){
			RecordFrase record(id, (*itrecord).getAutor(), (*itrecord).getFrase());
		    char bufferArray[long_frase];
		    unsigned int offset = 0;
		    record.serializar(bufferArray, offset);
		    archivo.write(bufferArray,long_frase);
		    bufferMapa[id-1] = '1';
		    id++;
		}
	}
	archivo.ir_al_principio();
    archivo.write(bufferMapa, long_mapa);
    archivo.ir_al_principio();

	//listar en archivo de texto
	ArchivoDeTexto listado("F-listado.txt",W);
	int i = 0;

	while(!archivo.is_EOF()){
		if(i == 0){
			char bufferArray[long_mapa];
			archivo.read(bufferArray, long_mapa);
			listado.escribirLinea(string(bufferArray));
		}
		if (i > 0 and !archivo.is_EOF()){
			char bufferArray[long_frase];
			unsigned int offset = 0;
			archivo.read(bufferArray, long_frase);
			RecordFrase record;
			record.deserializar(bufferArray, offset);
			listado.escribirLinea(record.toString());
		}
		i++;
	}
	}catch(exception &e){
		cout << e.what() << endl;
	}
}

/* normaliza todos los terminos del diccionario y quita las stopwords */
void ProcesadordeTareas::normalizar_diccionario(){
	DictionaryManager dictionary(this->path_diccionario);
	this->logger->log(DEBUG, this->directorio_raiz + PATH_DICC_NORMALIZADO);
	dictionary.obtenerCopiaNormalizada(this->directorio_raiz + PATH_DICC_NORMALIZADO, this->path_stopwords);
}

/* asigna un identificador aleatorio a cada termino del diccionario y genera dos archivos .bin y .txt */
void  ProcesadordeTareas::indexar_diccionario_aleatorio(){
	Indexador indexador(this->directorio_raiz + PATH_DICC_NORMALIZADO, this->directorio_raiz + PATH_DICC_INDEXADO);
	indexador.indexar_archivo();
}

/* ordena por indice el archivo del diccionario indexado */
void ProcesadordeTareas::ordenar_diccionario_aleatorio(){
	Sort external_sort(this->directorio_raiz + PATH_DICC_ORDENADO);
	external_sort.sort(this->directorio_raiz + PATH_DICC_INDEXADO_BIN, this->directorio_raiz + DIR_PARTICIONES, this->directorio_raiz + DIR_MERGE);
}

string ProcesadordeTareas::get_path_arbol(){
	return this->path_arbol;
}

void ProcesadordeTareas::crear_arbol(bool precargado, int  m){

	if (precargado){
		this->cargar_arbol_default();
	}
	else{
		this->path_arbol = this->directorio_raiz + PATH_ARBOL;
		this->arbol = new ArbolBMas(this->path_arbol, m);
		this->terminos_guardados = 0;
	}
}

void ProcesadordeTareas::cargar_arbol_default(){
	this->path_arbol = DIR_DEFAULT_ARBOL + "/" + PATH_ARBOL;
	this->arbol = new ArbolBMas(this->path_arbol, M_DEFAULT_ARBOL);
	this->terminos_guardados = 7046;
}


/* carga el arbol con los terminos del diccionario indexado y ordenado */
void ProcesadordeTareas::cargar_arbol_terminos(){

	if (this->arbol == NULL)
		throw NotNullException("Falta crear el arbol");

	ArchivoBinario file(this->directorio_raiz + PATH_DICC_ORDENADO, R);

	int id = 0;
	string num_aleat = "";
	string termino = "";
	while(!file.is_EOF()){
		num_aleat = file.obtenerLinea();
		termino = num_aleat.substr(LONG_INDICE, num_aleat.length() - 1);
		RecordTermino rec(id, termino);
		this->arbol->insertar(&rec);
		id++;
		cout << "inserte " << rec.getTermino() << endl;
	}
	this->terminos_guardados = id;
}

/* guarda un termino - si ya existe lanza una exception */
void ProcesadordeTareas::insertar_termino(string termino, string num){
	Palabra::normalizar(termino);
	int id = this->terminos_guardados;
	RecordTermino rec(id, termino + num);
	if (this->arbol->insertar(&rec)){
		this->terminos_guardados++;
	}
	else{
		throw exception();
	}
}

/* realiza la busqueda del termino, si no lo encuentra devuelve el siguiente */
string ProcesadordeTareas::buscar_termino(string termino){
	Palabra::normalizar(termino);
	RecordTermino * registro = this->arbol->buscar(termino);
	string ret =  registro->toString();
	delete registro;
	return ret;
}

/* crea un archivo en la carpeta del arbol con todos los terminos */
void ProcesadordeTareas::reporte_terminos_ordenados(){
	this->arbol->EscribirListadoOrdenado();
}

/* crea un archivo en la carpeta del arbol con la estructura final de sus nodos */
void ProcesadordeTareas::reporte_estructura_arbol(){
	this->arbol->MostrarArbol();
}

string ProcesadordeTareas::get_path_hash(){
	return this->path_hash;
}

/* inserta una nueva frase si es duplicada arroja una exception*/
void ProcesadordeTareas::insertar_frase(int clave, string nombre_autor, string apellido_autor, string frase){
	RecordFrase record(clave, nombre_autor, apellido_autor, frase);
	this->hash->insertar_registro(record);
}

/* busca un registro por clave, si no lo encuentra arroja una exception*/
string ProcesadordeTareas::buscar_frase(int clave){
	return this->hash->obtener_registro(clave).toString();
}

/* modifica un registro, si no lo encuentra arroja una exception*/
void ProcesadordeTareas::modificar_frase(int clave, string nombre_autor, string apellido_autor, string frase){
	RecordFrase record(clave, nombre_autor, apellido_autor, frase);
	this->hash->modificar_registro(record);
}

/* elimina una frase, si no la encuentra arroja una exception*/
void ProcesadordeTareas::eliminar_frase(int clave){
	this->hash->borrar_registro(clave);
}


/* crea un archivo con los datos del hash */
void ProcesadordeTareas::reporte_cubos(){
	this->hash->download(this->path_hash);
}

/* por cada frase cuenta los terminos no repetidos que en ella aparecen sacando las stopwords */
float ProcesadordeTareas::estadistica_terminos_promedio_por_frase(){

	int cantidad_frases = 0;
	int cantidad_terminos = 0;
	for (int i = 0; i < this->hash->get_cantidad_cubos(); i++){
		list<RecordFrase>::iterator itrecord;
		list<RecordFrase> frases = this->hash->get_frases_en_cubo(i);
		for(itrecord = frases.begin(); itrecord != frases.end(); ++itrecord){
			cantidad_frases++;
			list<string> terminos = Palabra::separar_cadena((*itrecord).getFrase()->toString());
			list<string>::iterator ittermino;
			for(ittermino = terminos.begin(); ittermino != terminos.end(); ++ittermino){
				StopWords sw(this->path_stopwords);
				if(!sw.is_StopWords(*ittermino))
					cantidad_terminos++;
			}
		}
	}
	return (cantidad_terminos / cantidad_frases);
}


float ProcesadordeTareas::estadistica_tasa_de_fallos(){
	int cantidad_terminos = 0;
	int cantidad_no_encontrados = 0;

	for (int i = 0; i < this->hash->get_cantidad_cubos(); i++){
		list<RecordFrase>::iterator itrecord;
		list<RecordFrase> frases = this->hash->get_frases_en_cubo(i);
		for(itrecord = frases.begin(); itrecord != frases.end(); ++itrecord){
			list<string> terminos = Palabra::separar_cadena((*itrecord).getFrase()->toString());
			list<string>::iterator ittermino;
			terminos.sort();   //ordena los terminos
			terminos.unique(); //elimina los terminos repetidos
			for(ittermino = terminos.begin(); ittermino != terminos.end(); ++ittermino){
				StopWords sw(this->path_stopwords);
				if(!sw.is_StopWords(*ittermino)){
					cantidad_terminos++;
					RecordTermino * record = this->arbol->buscar(*ittermino);
					string encontrado = record->getTermino();
					encontrado = encontrado.substr(0, encontrado.length() - 2);
					//Palabra::remove_character_to_end(' ', encontrado);
					if ((*ittermino).compare(encontrado) != 0)
						cantidad_no_encontrados++;
				}

			}
		}
	}

	return (cantidad_no_encontrados * 100 / cantidad_terminos);
}

list<string> ProcesadordeTareas::lista_terminos_no_encontrados(){
	list<string> resultado;

	for (int i = 0; i < this->hash->get_cantidad_cubos(); i++){
		list<RecordFrase>::iterator itrecord;
		list<RecordFrase> frases = this->hash->get_frases_en_cubo(i);
		for(itrecord = frases.begin(); itrecord != frases.end(); ++itrecord){
			list<string> terminos = Palabra::separar_cadena((*itrecord).getFrase()->toString());
			list<string>::iterator ittermino;
			terminos.sort();
			terminos.unique();
			for(ittermino = terminos.begin(); ittermino != terminos.end(); ++ittermino){
				StopWords sw(this->path_stopwords);
				if(!sw.is_StopWords(*ittermino)){
					RecordTermino * record = this->arbol->buscar(*ittermino);
					string encontrado = record->getTermino();
					encontrado = encontrado.substr(0, encontrado.length() - 2);
					if ((*ittermino).compare(encontrado) != 0)
						resultado.push_back(*ittermino);
				}

			}
		}
	}

	resultado.sort();
	resultado.unique();
	return resultado;
}


list<string> ProcesadordeTareas::lista_ranking_terminos_populares(int n){
	list<AuxiliarEstadisticaRanking> unique_terminos;
	list<AuxiliarEstadisticaRanking>::iterator itunique;
	for (int i = 0; i < this->hash->get_cantidad_cubos(); i++){
		list<RecordFrase>::iterator itrecord;
		list<RecordFrase> frases = this->hash->get_frases_en_cubo(i);
		for(itrecord = frases.begin(); itrecord != frases.end(); ++itrecord){
			list<string> terminos = Palabra::separar_cadena((*itrecord).getFrase()->toString());
			list<string>::iterator ittermino;
			for(ittermino = terminos.begin(); ittermino != terminos.end(); ++ittermino){
				StopWords sw(this->path_stopwords);
				if(!sw.is_StopWords(*ittermino)){
					bool encontrado = false;
					for(itunique = unique_terminos.begin(); itunique != unique_terminos.end(); ++itunique){
						if ((*ittermino).compare((*itunique).get_termino()) == 0){
							encontrado = true;
							AuxiliarEstadisticaRanking aux((*itunique).get_termino(), (*itunique).get_cantidad() + 1);
							unique_terminos.erase(itunique);
							unique_terminos.push_back(aux);
							break;
						}
						else{
							encontrado = false;
						}
					}
					if(!encontrado){
						AuxiliarEstadisticaRanking aux((*ittermino), 1);
						unique_terminos.push_back(aux);
					}

				}
			}
		}
	}

	unique_terminos.sort(greater<AuxiliarEstadisticaRanking>());
	list<string> result_ordenado;
	int contador = 0;
	for(itunique = unique_terminos.begin(); itunique != unique_terminos.end(); ++itunique){
		if (contador == n)
			break;
		result_ordenado.push_back((*itunique).toString());
		contador++;
	}

	return result_ordenado;
}

/* destructor */
ProcesadordeTareas::~ProcesadordeTareas(){
	delete(this->arbol);
	delete(this->hash);
}


